package elec315.chatroom.core.processor;

import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import elec315.chatroom.msg.BaseMsg;
import elec315.chatroom.msg.MsgId;
import elec315.chatroom.msg.ReturnCode;
import elec315.chatroom.msg.authentication.ChatLoginNtyMsg;
import elec315.chatroom.msg.authentication.ChatLoginReqMsg;
import elec315.chatroom.msg.authentication.ChatLoginResMsg;
import elec315.chatroom.msg.authentication.ChatLogoutNtyMsg;
import elec315.chatroom.msg.authentication.ChatLogoutReqMsg;
import elec315.chatroom.msg.authentication.ChatLogoutResMsg;
import elec315.chatroom.msg.chat.ChatBroadcastNtyMsg;
import elec315.chatroom.msg.chat.ChatBroadcastReqMsg;
import elec315.chatroom.msg.user.ChatGetUserListReqMsg;
import elec315.chatroom.msg.user.ChatGetUserListResMsg;
import elec315.chatroom.net.ServerSocketHandler;
import elec315.chatroom.net.SocketHandler;

public class ServerMessageProcessor implements MessageProcessor {

	private static final Log logger = LogFactory.getLog(ServerMessageProcessor.class);

	private final List<String> userIds;

	public ServerMessageProcessor(List<String> userIds) {
		this.userIds = userIds;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see elec315.chatroom.core.processor.MessageProcessor#process(elec315.chatroom.msg.BaseMsg,
	 *      elec315.chatroom.net.SocketHandler)
	 */
	public void process(BaseMsg baseMsg, SocketHandler socketHandler) {
		ServerSocketHandler serverSocketHandler = (ServerSocketHandler) socketHandler;
		MsgId msgId = baseMsg.getMsgId();

		switch (msgId) {
		case CHAT_REQ_LOGIN: {
			ChatLoginReqMsg reqMsg = (ChatLoginReqMsg) baseMsg;
			processChatLoginReqMsg(reqMsg, serverSocketHandler);
			break;
		}
		case CHAT_REQ_LOGOUT: {
			ChatLogoutReqMsg reqMsg = (ChatLogoutReqMsg) baseMsg;
			processChatLogoutReqMsg(reqMsg, serverSocketHandler);
			break;
		}
		case CHAT_REQ_BROADCAST: {
			ChatBroadcastReqMsg reqMsg = (ChatBroadcastReqMsg) baseMsg;
			processChatBroadcastReq(reqMsg, serverSocketHandler);
			break;
		}
		case CHAT_REQ_GET_USER_ID_LIST: {
			ChatGetUserListReqMsg reqMsg = (ChatGetUserListReqMsg) baseMsg;
			prcessChatGetUserListReqMsg(reqMsg, serverSocketHandler);
			break;
		}
		default:
			logger.error("Unhandled msgId: " + msgId);
			break;
		}
	}

	private void processChatLoginReqMsg(ChatLoginReqMsg reqMsg, ServerSocketHandler serverSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received reqMsg: " + reqMsg);
		}

		ChatLoginResMsg resMsg = null;
		ChatLoginNtyMsg ntyMsg = null;
		ReturnCode returnCode = null;
		String userId = reqMsg.getUserId();

		if (StringUtils.isNotBlank(userId)) {
			returnCode = ReturnCode.SUCESS;
			serverSocketHandler.setUserId(userId);
			resMsg = new ChatLoginResMsg(reqMsg.getReqByUserId(), new Date(), returnCode, userId);
			ntyMsg = new ChatLoginNtyMsg(reqMsg.getReqByUserId(), new Date(), userId);
			userIds.add(userId);
		} else {
			returnCode = ReturnCode.FAIL;
			resMsg = new ChatLoginResMsg(reqMsg.getReqByUserId(), new Date(), returnCode, userId);
		}
		try {
			serverSocketHandler.writeMessage(resMsg);
			if (returnCode == ReturnCode.SUCESS) {
				serverSocketHandler.broadcastMessage(ntyMsg);
			}
		} catch (Exception ex) {
			logger.error(ex, ex);
		}
	}

	private void processChatLogoutReqMsg(ChatLogoutReqMsg reqMsg, ServerSocketHandler serverSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received reqMsg: " + reqMsg);
		}
		ChatLogoutResMsg resMsg = null;
		ChatLogoutNtyMsg ntyMsg = null;
		ReturnCode returnCode = null;
		String userId = reqMsg.getUserId();

		if (StringUtils.isNotBlank(userId)) {
			returnCode = ReturnCode.SUCESS;
			resMsg = new ChatLogoutResMsg(reqMsg.getReqByUserId(), new Date(), returnCode, userId);
			ntyMsg = new ChatLogoutNtyMsg(reqMsg.getReqByUserId(), new Date(), userId);
			userIds.remove(userId);
		} else {
			returnCode = ReturnCode.FAIL;
			resMsg = new ChatLogoutResMsg(reqMsg.getReqByUserId(), new Date(), returnCode, userId);
		}
		try {
			serverSocketHandler.broadcastMessage(resMsg);
			serverSocketHandler.removeObserver(serverSocketHandler);
			if (returnCode == ReturnCode.SUCESS) {
				serverSocketHandler.broadcastMessage(ntyMsg);
			}
		} catch (Exception ex) {
			logger.error(ex, ex);
		}
	}

	private void processChatBroadcastReq(ChatBroadcastReqMsg reqMsg, ServerSocketHandler serverSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received reqMsg: " + reqMsg);
		}
		ChatBroadcastNtyMsg ntyMsg = new ChatBroadcastNtyMsg(reqMsg.getReqByUserId(), new Date(), reqMsg.getUserId(),
				reqMsg.getMessage());
		try {
			serverSocketHandler.broadcastMessage(ntyMsg);
		} catch (Exception ex) {
			logger.error(ex, ex);
		}
	}

	private void prcessChatGetUserListReqMsg(ChatGetUserListReqMsg reqMsg, ServerSocketHandler serverSocketHandler) {
		if (logger.isDebugEnabled()) {
			logger.debug("Received reqMsg: " + reqMsg);
		}
		ChatGetUserListResMsg resMsg = new ChatGetUserListResMsg(reqMsg.getReqByUserId(), new Date(),
				ReturnCode.SUCESS, userIds);
		try {
			serverSocketHandler.writeMessage(resMsg);
		} catch (Exception ex) {
			logger.error(ex, ex);
		}
	}

}
